/*
 *  Copyright 2008 The MITRE Corporation (http://www.mitre.org/). All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.mitre.lattice.util;

import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferUShort;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.InputStream;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.sql.Statement;
import java.util.Iterator;
import java.util.logging.Logger;
import java.util.zip.GZIPOutputStream;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.FileImageOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.fileupload.*;
import org.mitre.mrald.util.Config;
import org.mitre.mrald.util.MraldException;
import org.mitre.mrald.util.User;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *@author     ghamilton
 *@created    April 5, 2004
 */
public class ImageUtils
{
    /**
     *  Description of the Field
     */
    public final static String KEY = ImageUtils.class.getName();
    /**
     *  Description of the Field
     */
    public final static Logger log = Logger.getLogger( KEY );
    // String FINDUSER = "select * from People where (People.email='<:username:>@mitre.org' OR People.email='<:username:>')";
    /**
     *  Description of the Field
     */
    protected Connection conn;
    /**
     *  Description of the Field
     */
    protected Statement s;


    /**
     *  Constructor for the FormUtils object
     *
     *@since
     */
    public ImageUtils() { }


    /**
     *  Description of the Method
     *
     *@param  temp             Description of the Parameter
     *@return                  The redirect value
     *@exception  IOException  Description of the Exception
     */
    public static String getRedirect( String temp )
        throws IOException
    {
        /*
         *  Get the Redirect for the Form
         */
        String base = Config.getProperty( "BasePath" );
        String redirectFile = temp.substring( base.length() );
        return ( Config.getProperty( "BaseUrl" ) + "/" + redirectFile );
    }


    /**
     *  Description of the Method
     *
     *@exception  java.sql.SQLException  Description of the Exception
     */
    public void close()
        throws java.sql.SQLException
    {
        s.close();
        conn.close();
    }


    /**
     *  Sets the imageData attribute of the ImageFileDecoder object
     *
     *@param  file                          Description of the Parameter
     *@param  fileName                      Description of the Parameter
     *@return                               The imageData value
     *@exception  FileNotFoundException     Description of the Exception
     *@exception  IOException               Description of the Exception
     *@exception  IllegalArgumentException  Description of the Exception
     *@exception  MraldException            Description of the Exception
     */
    public File getImageData( File file, String fileName )
        throws FileNotFoundException, IOException, IllegalArgumentException, MraldException
    {
        ImageReader imagereader = getImageReader( file );
        if ( imagereader == null )
        {
            log.info( "No image reader found for this file format." );
            throw new MraldException( "No image reader found for this file format." );
        }
        java.awt.image.BufferedImage image = null;
        int noImages = imagereader.getNumImages( true );
        int offset = 0;
        java.io.File rawFile = new java.io.File( fileName );
        FileImageOutputStream outFile = new FileImageOutputStream( rawFile );
        for ( int i = 0; i < noImages; i++ )
        {
            image = imagereader.read( i );
            //boolean success =
            writeOut( image, outFile, offset );
            if ( image == null )
            {
                log.info( "The image could not be written out." );
                throw new MraldException( "The image could not be written out." );
            }
        }
        outFile.close();
        return rawFile;
    }


    /**
     *  Description of the Method
     *
     *@param  image                      Description of the Parameter
     *@param  outFile                    Description of the Parameter
     *@param  offSet                     Description of the Parameter
     *@return                            Description of the Return Value
     *@exception  FileNotFoundException  Description of the Exception
     *@exception  IOException            Description of the Exception
     */
    private static boolean writeOut( java.awt.image.BufferedImage image, FileImageOutputStream outFile, int offSet )
        throws FileNotFoundException, IOException
    {
        DataBuffer dataBuffer = image.getRaster().getDataBuffer();
        if ( dataBuffer.getDataType() == DataBuffer.TYPE_BYTE )
        {
            byte[] data = ( ( DataBufferByte ) dataBuffer ).getData();
            int len = data.length;
            outFile.write( data, 0, len );
        }
        else if ( dataBuffer.getDataType() == DataBuffer.TYPE_USHORT )
        {
            short[] data = ( ( DataBufferUShort ) dataBuffer ).getData();
            int len = data.length;
            outFile.writeShorts( data, 0, len );
        }
        outFile.flush();
        return true;
    }


    /**
     *  Description of the Method
     *
     *@param  file                       Description of the Parameter
     *@return                            Description of the Return Value
     *@exception  FileNotFoundException  Description of the Exception
     *@exception  IOException            Description of the Exception
     */
    protected static ImageReader getImageReader( File file )
        throws FileNotFoundException, IOException
    {
        FileImageInputStream fileimageinputstream = new FileImageInputStream( file );
        Object obj = fileimageinputstream;
        Iterator iterator = ImageIO.getImageReaders( obj );
        if ( !iterator.hasNext() )
        {
            obj = file;
            iterator = ImageIO.getImageReaders( obj );
            if ( !iterator.hasNext() )
            {
                obj = fileimageinputstream;
                String as[] = file.getName().split( "\\." );
                if ( as.length > 1 )
                {
                    iterator = ImageIO.getImageReadersBySuffix( as[as.length - 1] );
                }
                if ( !iterator.hasNext() )
                {
                    return null;
                }
            }
        }
        ImageReader imagereader = ( ImageReader ) iterator.next();
        imagereader.setInput( obj );
        return imagereader;
    }


    /**
     *  Description of the Method
     *
     *@param  xmlFile          Description of the Parameter
     *@return                  Description of the Return Value
     *@exception  IOException  Description of the Exception
     */
    public org.w3c.dom.Node createDom( String xmlFile )
        throws IOException
    {
        try
        {
            Reader reader = new BufferedReader( new FileReader( xmlFile ) );
            DocumentBuilderFactory factory =
                DocumentBuilderFactory.newInstance();
            InputSource datafile = new InputSource( reader );
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse( datafile );
            return document.getDocumentElement();
        }
        catch ( SAXException sxe )
        {
            // Error generated by this application
            // (or a parser-initialization error)
            throw new RuntimeException( "\n** SAXException error " + sxe.getMessage() );
        }
        catch ( ParserConfigurationException pce )
        {
            // Parser with specified options can't be built
            throw new RuntimeException( "\n** ParseConfiguration error " + pce.getMessage() );
        }
    }


    /**
     *  Stores the image to disk. Note this will handle only one file at a time.
     *  If you want to upload more than one image, you'll have to rework this.
     *  The first non-form item encountered (a file field) is the one taken.
     *
     *@param  req                      Request that contains the upload
     *@param  user                     Description of the Parameter
     *@return                          Description of the Return Value
     *@exception  JspException         Description of the Exception
     *@exception  FileUploadException  Description of the Exception
     *@exception  IOException          Description of the Exception
     *@exception  Exception            Description of the Exception
     *@since
     */
    public boolean storeImage( HttpServletRequest req, User user )
        throws JspException, FileUploadException, IOException, Exception
    {
        return true;
    }


    /**
     *  Simple download file, that takes file 'As is and returns to user'
     *
     *@param  res                        Description of the Parameter
     *@param  fileName                   Description of the Parameter
     *@exception  IOException            Description of the Exception
     *@exception  FileNotFoundException  Description of the Exception
     *@exception  Exception              Description of the Exception
     */
    public void downLoadFile( HttpServletResponse res, String fileName )
        throws IOException, FileNotFoundException, Exception
    {
//        String s;
        File f = new File(fileName);
        String justFileName = f.getName();
        try
        {
            InputStream in = new FileInputStream( fileName );
            GZIPOutputStream out = new GZIPOutputStream( res.getOutputStream() );
            res.setContentType( "application/text" );
            res.setHeader( "Content-Disposition", "attachment; filename=" + justFileName + ".gz;" );
            byte[] buffer = new byte[1024];
            while ( true )
            {
                int len = in.read( buffer );
                if ( len < 0 )
                {
                    break;
                }
                out.write( buffer, 0, len );
            }
            out.flush();
            out.close();
            in.close();
        }
        catch ( Exception e )
        {
            throw e;
        }
        //Temporary test
        //downLoadFile();
    }


    /**
     *  Simple download file, that takes file 'As is and returns to user'
     *
     *@param  fileName                   Description of the Parameter
     *@param  outFileName                Description of the Parameter
     *@exception  IOException            Description of the Exception
     *@exception  FileNotFoundException  Description of the Exception
     *@exception  Exception              Description of the Exception
     */
    public void downLoadFile( String outFileName, String fileName )
        throws IOException, FileNotFoundException, Exception
    {
//        String s;
        try
        {
            java.io.InputStream in = new java.io.FileInputStream( fileName );
            java.io.FileOutputStream out = new java.io.FileOutputStream( new File( outFileName ) );
            byte[] buffer = new byte[1024];
            while ( true )
            {
                int len = in.read( buffer );
                if ( len < 0 )
                {
                    break;
                }
                out.write( buffer, 0, len );
            }
            out.flush();
            out.close();
            in.close();
        }
        catch ( Exception e )
        {
            throw e;
        }
        //Temporary test
        //downLoadFile();
    }


    /**
     *  This method takes the rar data and creates a header file. from the xml
     *  file created when the file was initially uploaded. THis xml file can be
     *  applied back to the file to recreate it (deanomyized).
     *
     *@param  xmlFile                    Description of the Parameter
     *@param  imageFileName              Description of the Parameter
     *@param  outputFileName             Description of the Parameter
     *@exception  IOException            Description of the Exception
     *@exception  FileNotFoundException  Description of the Exception
     */
    protected void downLoadFileEx( String xmlFile, String imageFileName, String outputFileName )
        throws IOException, FileNotFoundException
    {
    }


    /**
     *  Description of the Method
     *
     *@param  fileName         Description of the Parameter
     *@exception  IOException  Description of the Exception
     */
    /*
     *  public void writeImageData(String format, String fileName)
     *  throws IOException
     *  {
     *  String xmlFile = fileName.substring(0, fileName.indexOf(".")) + ".xml";
     *  ImageWriter imagewriter = getImageWriter("ucla");
     *  IIOMetadata metaData = imagewriter.getDefaultImageMetadata(null, null);
     *  org.w3c.dom.Node node = createDom(xmlFile);
     *  metaData.mergeTree(format, node);
     *  BufferedImage bufferedimage = getData(fileName);
     *  IIOImage image = new IIOImage(bufferedimage, null, metaData);
     *  imagewriter.write(metaData, image, null);
     *  }
     */
    /*
     *  Description of the Method
     *
     *  @param  iiometadata      Description of the Parameter
     *  @param  imagetree        Description of the Parameter
     *  @exception  IOException  Description of the Exception
     */
    /**
     *  Gets the data attribute of the ImageUtils object
     *
     *@param  fileName         Description of the Parameter
     *@exception  IOException  Description of the Exception
     */
    public void getData( String fileName )
        throws IOException
    {
        File file = new File( fileName );
        ImageReader imagereader = getImageReader( file );
        int noImages = imagereader.getNumImages( true );
        for ( int i = 0; i < noImages; i++ )
        {
            imagereader.read( i );
        }
    }


    /**
     *  Gets the imageWriter attribute of the ImageFileEncoder class
     *
     *@param  imageFormat      Description of the Parameter
     *@return                  The imageWriter value
     *@exception  IOException  Description of the Exception
     */
    public static ImageWriter getImageWriter( String imageFormat )
        throws IOException
    {
        IIORegistry iioregistry = IIORegistry.getDefaultInstance();
        for ( Iterator iterator = iioregistry.getServiceProviders( javax.imageio.spi.ImageWriterSpi.class, true ); iterator.hasNext();  )
        {
            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "ImageUtils: getImageWriter: Getting imageWRiters :");
            ImageWriterSpi imagewriterspi = ( ImageWriterSpi ) iterator.next();
            String tryFormat = imagewriterspi.getNativeImageMetadataFormatName();
            //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "ImageUtils: getImageWriter: Trying Format :" + tryFormat);
            if ( tryFormat == null )
            {
                continue;
            }
            if ( imageFormat.equals( tryFormat ) )
            {
                //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "ImageUtils: getImageWriter: Format found. " + tryFormat);
                if ( tryFormat.indexOf( imageFormat ) > 0 )
                {
                    return imagewriterspi.createWriterInstance();
                }
            }
        }
//        String s2 = "Cannot find an Image Writer for the target." + imageFormat;
        //MraldOutFile.logToFile(Config.getProperty("LOGFILE"), "ImageUtils: getImageWriter: NO format. " + s2);
        return null;
        //throw new IIOException(s2);
    }
}

